﻿using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;


public class DrawWithBrush: MonoBehaviour
{
    public Texture2D BrushTex;
    public float a = 0.25f;
    public Renderer _render;
    public Texture2D m_TargetTex;
    private Texture2D m_DrawingTex;
    private Collider m_PaintCollider;
    private Color32[] m_TargetPixels;
    private Color32[] m_BrushPiexls;
    private Color32[] m_DrawingPiexls;
    private Vector2 m_CurUV;
    private Vector2 m_OldUV;
    private int m_BrushWidth;       //
    private int m_BrushHeight;      //
    private int m_BrushHalfWidth;   //刷子图片半宽
    private int m_BrushHalfHeight;  //刷子图片半高
    private int m_TargetTexWidth;   //被填色的图片的宽度
    private int m_TargetTexHeight;//被填色的图片的高度
    private bool m_StartDrawing;
    private Color32 m_CurColor;
    private bool m_EraserModel;
    public Camera m_AniCamera;
    private LayerMask mask = 1 << 21;
    private int startId = 500000;
  
    private Camera AniCamera
    {
        get
        {
            return m_AniCamera;

        }
    }

    private void Awake()
    {
        //填充蒙版为黑色透明
        m_DrawingTex = new Texture2D(m_TargetTex.width, m_TargetTex.height, TextureFormat.ARGB32, false, false);
        m_DrawingTex.filterMode = FilterMode.Point;
        m_DrawingPiexls = m_DrawingTex.GetPixels32();
        int count = m_DrawingPiexls.Length;
        for (int i = 0; i < count; i++)
        {
            m_DrawingPiexls[i].r = 0;
            m_DrawingPiexls[i].g = 0;
            m_DrawingPiexls[i].b = 0;
            m_DrawingPiexls[i].a = 0;
        }
        m_DrawingTex.SetPixels32(m_DrawingPiexls);
        m_DrawingTex.Apply(false);

        //targetTexture
        m_TargetPixels = m_TargetTex.GetPixels32();
        m_TargetTexWidth = m_TargetTex.width;
        m_TargetTexHeight = m_TargetTex.height;

        //设置贴图
        _render.material.shader = Shader.Find("Unlit/DrawingShader");
        _render.material.SetTexture("_MaskTex", m_DrawingTex);
        _render.material.SetTexture("_MainTex", m_TargetTex);

        //笔刷
        m_CurColor = Color.red;

        m_BrushWidth = BrushTex.width;
        m_BrushHeight = BrushTex.height;
        m_BrushHalfWidth = (int)(m_BrushWidth / 2);
        m_BrushHalfHeight = (int)(m_BrushHeight / 2);
        m_BrushPiexls = BrushTex.GetPixels32();

        //ajust_size
        float radio = m_TargetTex.width / (float)m_TargetTex.height;
        Vector2 local_size = GetLocalSize(radio);
        _render.transform.localScale = new Vector3(local_size.x, local_size.y, 1);

    }

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            if (!m_StartDrawing)
            {
                m_StartDrawing = true;
                TouchBegin(Input.mousePosition);
            }
            else
            {
                TouchMove(Input.mousePosition);
            }
        }
        else if (Input.GetMouseButtonUp(0))
        {
            TouchEnd(Input.mousePosition);
        }

    }

    private void EndToFillingPixels()
    {
        int width = m_DrawingTex.width;
        int height = m_DrawingTex.height;
        int pixel = 0;

        pixel = 0;
        Color32 w = new Color32(255, 252, 239, 255);
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                if (m_TargetPixels[pixel].r > 220 && m_TargetPixels[pixel].a > 25)
                {
                    if (m_DrawingPiexls[pixel].a < 10)
                    {
                        m_DrawingPiexls[pixel] = w;
                    }
                    else if (m_DrawingPiexls[pixel].a < 250)
                    {
                        m_DrawingPiexls[pixel] = Color32.Lerp(w, m_DrawingPiexls[pixel], m_DrawingPiexls[pixel].a / 255f);
                    }
                }

                pixel++;
            }
        }
        m_DrawingTex.SetPixels32(m_DrawingPiexls);
        m_DrawingTex.Apply(false);

    }

    private void DrawBrush(int px, int py)
    {
        //Debug.LogError("DrawBrush:" + px + "___" + py);
        int stX = Mathf.Clamp(px - m_BrushHalfWidth, 0, m_TargetTexWidth);
        int stY = Mathf.Clamp(py - m_BrushHalfHeight, 0, m_TargetTexHeight);
        int endX = Mathf.Clamp(px + m_BrushHalfWidth, 0, m_TargetTexWidth);
        int endY = Mathf.Clamp(py + m_BrushHalfHeight, 0, m_TargetTexHeight);

        int lengthX = endX - stX;
        int lengthY = endY - stY;

        int max = m_TargetTexWidth * m_TargetTexHeight - 1 - m_TargetTexWidth;
        int pixel = m_TargetTexWidth * stY + stX;   //当前刷子起始像素在目标图片的位置
        //Debug.LogError("pixel:" + pixel);
        int BrushPiexl;
        //float alpha = 0;
        byte maxalpha = 0;

        for (int y = 0; y < lengthY; y++)
        {
            for (int x = 0; x < lengthX; x++)
            {
                BrushPiexl = m_BrushWidth * y + x;

                if (m_EraserModel)
                {
                    if (m_BrushPiexls[BrushPiexl].a > 25)
                    {
                        //恢复颜色和透明度
                        m_DrawingPiexls[pixel] = Color32.Lerp(m_DrawingPiexls[pixel], m_CurColor, m_BrushPiexls[BrushPiexl].a / 255f); ;
                    }
                }
                else
                {
                    //这个区域有涂色但涂得不彻底
                    if (m_CurColor.r != m_DrawingPiexls[pixel].r && m_DrawingPiexls[pixel].r != 0)
                    {
                        if (m_BrushPiexls[BrushPiexl].a > 250)
                        {
                            m_DrawingPiexls[pixel] = m_CurColor;
                        }
                        else
                        {
                            m_DrawingPiexls[pixel] = Color32.Lerp(m_DrawingPiexls[pixel], m_CurColor, m_BrushPiexls[BrushPiexl].a / 255f);
                        }
                    }
                    else
                    {
                        maxalpha = m_BrushPiexls[BrushPiexl].a > m_DrawingPiexls[pixel].a ? m_BrushPiexls[BrushPiexl].a : m_DrawingPiexls[pixel].a;
                        m_DrawingPiexls[pixel] = m_CurColor;
                        m_DrawingPiexls[pixel].a = maxalpha;
                    }

                }

                pixel++;
            }
            pixel = Mathf.Clamp((m_TargetTexWidth * (stY + y + 1) + stX + 1), 0, max);
        }
    }

    private void DrawBrushAndSave(int px, int py)
    {
        DrawBrush(px, py);
        m_DrawingTex.SetPixels32(0, 0, m_TargetTexWidth, m_TargetTexHeight, m_DrawingPiexls, 0);
        m_DrawingTex.Apply(false);
    }

    private void DrawLineWithBrush(Vector2 start, Vector2 end)
    {
        int x0 = (int)start.x;
        int y0 = (int)start.y;
        int x1 = (int)end.x;
        int y1 = (int)end.y;
        int dx = Mathf.Abs(x1 - x0); // TODO: try these? http://stackoverflow.com/questions/6114099/fast-integer-abs-function
        int dy = Mathf.Abs(y1 - y0);
        int sx, sy;
        if (x0 < x1) { sx = 1; } else { sx = -1; }
        if (y0 < y1) { sy = 1; } else { sy = -1; }
        int err = dx - dy;
        bool loop = true;
        //			int minDistance=brushSize-1;
        int minDistance = (int)(m_BrushWidth / 4);
        int pixelCount = 0;
        int e2;
        while (loop)
        {
            pixelCount++;
            if (pixelCount > minDistance)
            {
                pixelCount = 0;
                DrawBrush(x0, y0);
            }
            if ((x0 == x1) && (y0 == y1)) loop = false;
            e2 = 2 * err;
            if (e2 > -dy)
            {
                err = err - dy;
                x0 = x0 + sx;
            }
            if (e2 < dx)
            {
                err = err + dx;
                y0 = y0 + sy;
            }
        }

    }


    public void TouchBegin(Vector3 inputScreenPosition)
    {
        RaycastHit hit;
        Physics.Raycast(AniCamera.ScreenPointToRay(inputScreenPosition), out hit, Mathf.Infinity);
        if (hit.collider != null)
        {
            m_CurUV = hit.textureCoord;
            m_CurUV.x *= m_TargetTexWidth;
            m_CurUV.y *= m_TargetTexHeight;
            //Debug.Log("TouchPhase.Began_m_CurUV:" + m_CurUV);
            //Debug.LogError("TouchPhase.Began");
            DrawBrushAndSave((int)m_CurUV.x, (int)m_CurUV.y);

            m_StartDrawing = true;
            m_OldUV = m_CurUV;
        }

    }

    public void TouchEnd(Vector3 inputScreenPosition)
    {
        if (m_StartDrawing)
        {
            Debug.Log("绘画结束");
            m_StartDrawing = false;
        }
        if (!m_StartDrawing)
        {
            Debug.Log("paint finished");
        }
    }

    public void TouchMove(Vector3 inputScreenPosition)
    {
        RaycastHit hit;
        Physics.Raycast(AniCamera.ScreenPointToRay(inputScreenPosition), out hit, Mathf.Infinity);
        if (hit.collider != null)
        {
            m_StartDrawing = true;
            m_OldUV = m_CurUV;
            m_CurUV = hit.textureCoord;
            if (m_OldUV == Vector2.zero)
            {
                m_OldUV = m_CurUV;
            }

            m_CurUV.x *= m_TargetTexWidth;
            m_CurUV.y *= m_TargetTexHeight;
            //Debug.LogError("TouchPhase.Moved_m_OldUV:" + m_OldUV + "m_CurUV" + m_CurUV);
            DrawBrush((int)m_CurUV.x, (int)m_CurUV.y);

            //Debug.LogError("m_OldUV:" + m_OldUV + "m_CurUV" + m_CurUV);
            if (Vector2.Distance(m_OldUV, m_CurUV) > (m_BrushWidth * 0.33f))
            {
                //Debug.LogError("DrawLineWithBrush:");
                DrawLineWithBrush(m_OldUV, m_CurUV);
            }
            m_DrawingTex.SetPixels32(0, 0, m_TargetTexWidth, m_TargetTexHeight, m_DrawingPiexls, 0);
            m_DrawingTex.Apply(false);
        }

    }

    private Vector2 GetLocalSize(float w_h_radio)
    {
        Vector2 size;
        if (w_h_radio >= 1)
        {
            size.x = w_h_radio;
            size.y = 1;
        }
        else
        {
            size.x = 1;
            size.y = 1 / w_h_radio;
        }
        return size;
    }

}